package com.caocaog.market.finance.entity;

import com.baomidou.mybatisplus.annotation.*;
import com.caocaog.market.finance.enums.WithdrawStatus;
import com.caocaog.market.finance.service.FinanceLineService;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.util.Assert;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;

import static com.caocaog.market.finance.enums.WithdrawStatus.*;

/**
 * 提现行
 */
@Data
@Accessors(chain = true)
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = false)
@TableName("mk_finance_line")
public class FinanceLine implements Serializable {
    private static final long serialVersionUID = 1L;


    @TableId(type = IdType.AUTO)
    private Long id;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    protected LocalDateTime createTime;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    protected LocalDateTime updateTime;
    @TableLogic
    protected Integer deleted;


    @NotBlank(message = "订单ID不能为空")
    private String orderId;
    @NotBlank(message = "订单编号不能为空")
    @Excel(name = "订单编号", width = 80)
    private String orderNo;
    @NotNull(message = "订单支付金额不能为空")
    @Excel(name = "订单支付金额", width = 40, type = 4, isStatistics = true)
    private BigDecimal payAmount;
    @NotNull(message = "订单支付时间不能为空")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @Excel(name = "订单支付时间", width = 40, databaseFormat = "yyyy-MM-dd HH-mm-ss")
    private LocalDateTime payTime;
    /**
     * 是否已结算 false未结算 true已结算 默认false
     */
    private Boolean settlement;


    @NotNull(message = "总部抽成比例不能为空")
    @TableField("system_PCT")
    @Excel(name = "总部抽成比例", width = 40)
    private BigDecimal systemPCT; // PCT（percentage 百分比）
    @Excel(name = "总部抽成金额", width = 40)
    private transient BigDecimal systemAmount;

    public FinanceLine calculateSystemAmount() {
        return setSystemAmount(payAmount.multiply(systemPCT).setScale(2, RoundingMode.DOWN));
    }


    @NotNull(message = "分站抽成比例不能为空")
    @TableField("site_PCT")
    @Excel(name = "分站抽成比例", width = 40)
    private BigDecimal sitePCT; // PCT（percentage 百分比）
    @Excel(name = "分站抽成金额", width = 40)
    private transient BigDecimal siteAmount;
    public FinanceLine calculateSiteAmount() {
        return setSiteAmount(payAmount.multiply(sitePCT).setScale(2, RoundingMode.DOWN));
    }
    /**
     * 分站提现状态 0待提现 1待审核 2待转账 3已提现 默认0
     */
    @Excel(name = "分站提现状态", width = 40, replace = {"待提现_0", "待审核_1", "待转账_2", "已提现_3"})
    private WithdrawStatus siteStatus;


    /**
     * 店铺抽成比例 = 1 - 总部抽成比例 - 分站抽成比例
     */
    @NotNull(message = "店铺抽成比例不能为空")
    @TableField("shop_PCT")
    @Excel(name = "店铺抽成比例", width = 40)
    private BigDecimal shopPCT; // PCT（percentage 百分比）

    /**
     * 计算店铺抽成比例
     */
    public FinanceLine calculateShopPCT() {
        if (systemPCT == null || sitePCT == null) return this;
        return setShopPCT(BigDecimal.ONE.subtract(systemPCT).subtract(sitePCT));
    }

    @Excel(name = "店铺抽成金额", width = 40)
    private transient BigDecimal shopAmount;

    public FinanceLine calculateShopAmount() {
        Assert.notNull(systemAmount, "总部抽成金额不能为空");
        Assert.notNull(siteAmount, "分站抽成金额不能为空");
        return setShopAmount(payAmount.subtract(systemAmount).subtract(siteAmount));
    }

    /**
     * 店铺提现状态 0待提现 1待审核 2待转账 3已提现 默认0
     */
    @Excel(name = "店铺提现状态", width = 40, replace = {"待提现_0", "待审核_1", "待转账_2", "已提现_3"})
    private WithdrawStatus shopStatus;


    /**
     * 查询参数
     */
    @Dict(dictTable = "mk_merchant_basic", dicText = "name", dicCode = "id")
    @Excel(name = "商户", width = 40, dictTable = "mk_merchant_basic", dicText = "name", dicCode = "id")
    private transient String merchantId; // 商家ID 当前登录用户为商家类型时此参数无效
    @Dict(dictTable = "mk_shop_basic", dicText = "name", dicCode = "id")
    @Excel(name = "店铺", width = 40, dictTable = "mk_merchant_basic", dicText = "name", dicCode = "id")
    private transient String shopId; // 店铺ID
    private transient String groupNo; // 提现组编号
    private transient String payTimeFrom;
    private transient String payTimeTo;
    private transient String siteName;


    /**
     * 是否可以修改抽成比例（前端所需的判断参数）
     */
    private transient Boolean updatablePCT;

    public FinanceLine setUpdatablePCT() {
        return setUpdatablePCT(isUpdatableSitePCT(this) && isUpdatableShopPCT(this));
    }


    /**
     * 是否可以修改分站抽成比例，只要分站的提现状态是「待转账」、「已提现」或「转账失败」，就不可以修改抽成比例
     */
    public static Boolean isUpdatableSitePCT(FinanceLine financeLine) {
        return financeLine.siteStatus != PENDING_TRANSFER && financeLine.siteStatus != FULLY_WITHDRAW && financeLine.siteStatus != TRANSFER_FAILED;
    }

    /**
     * 是否可以修改店铺抽成比例，只要店铺的提现状态是「待转账」、「已提现」或「转账失败」，就不可以修改抽成比例
     */
    public static Boolean isUpdatableShopPCT(FinanceLine financeLine) {
        return financeLine.shopStatus != PENDING_TRANSFER && financeLine.shopStatus != FULLY_WITHDRAW && financeLine.shopStatus != TRANSFER_FAILED;
    }


    /**
     * 清除数据
     * 在{@link FinanceLineService#updateFinanceLine(FinanceLine) 更新提现组}时，避免修改到固定字段
     */
    public FinanceLine clearFields() {
        createTime = null;
        updateTime = null;
        deleted = null;
        orderId = null;
        orderNo = null;
        payAmount = null;
        payTime = null;
        return this;
    }

}
